<script lang="ts" setup>
import { onMounted, onUnmounted, reactive } from 'vue'
import { SelectOption, useMessage } from 'naive-ui'
import { getAll } from '@tauri-apps/api/window'
import { invoke_proxy } from '@/functions/invoke.ts'
import { BackendResponse } from '@/runtime/response.ts'
import { ComponentV2rayInfo, ComponentV2rayProxyMode, ComponentV2rayState } from '@/models/components/v2ray/v2ray_info.ts'
import { BACKEND_CODE_OK } from '@/runtime/code.ts'
import { SelectBaseOption } from 'naive-ui/es/select/src/interface'
import { ComponentV2rayVersion } from '@/models/components/v2ray/v2ray_version.ts'
import { ComponentV2rayBasicSetting, new_component_v2ray_basic_setting } from '@/models/components/v2ray/v2ray_basic_setting.ts'
import { dbus } from '@/dbus/dbus.ts'
import { ComponentV2rayServer } from '@/models/components/v2ray/v2ray_server.ts'
import { copy_to_clipboard } from '@/functions/clipboard.ts'
import { appDataDir, join } from '@tauri-apps/api/path'
import { ComponentV2rayRouter } from '@/models/components/v2ray/v2ray_router.ts'
import ComponentV2rayAddRouter from '@/views/components/ComponentV2rayAddRouter.vue'
import ComponentV2rayServerManagement from '@/views/components/ComponentV2rayServerManagement.vue'
import ComponentV2rayCopyLocalProxy from '@/views/components/ComponentV2rayCopyLocalProxy.vue'

declare type State = {
    version: string
    versions: SelectOption[]
    versions_loading: boolean
    select: string | undefined
    modes: SelectBaseOption<ComponentV2rayProxyMode>[]
    basic_setting: ComponentV2rayBasicSetting
    state: ComponentV2rayState
    installing: boolean
    basic_setting_saving: boolean
    geosite_updating: boolean
    servers: ComponentV2rayServer[]
    routers: ComponentV2rayRouter[]
    switching: boolean
    auto_refresh: NodeJS.Timeout | undefined
    install_stage: string
    install_percent: number
    actioning: boolean
}
const state = reactive<State>({
    version: '-',
    versions: [],
    versions_loading: true,
    select: undefined,
    modes: [
        { label: '路由模式', value: ComponentV2rayProxyMode.Router },
        { label: '全局模式', value: ComponentV2rayProxyMode.Global },
        { label: '手动模式', value: ComponentV2rayProxyMode.Manual },
    ],
    basic_setting: new_component_v2ray_basic_setting(),
    state: ComponentV2rayState.NotInstall,
    installing: false,
    basic_setting_saving: false,
    geosite_updating: false,
    servers: [],
    routers: [],
    switching: false,
    auto_refresh: undefined,
    install_stage: '',
    install_percent: 0,
    actioning: false,
})

onMounted(async () => {
    window.Message = useMessage()

    // 监听键盘释放事件
    document.onkeydown = async (event: KeyboardEvent) => {
        if ('w' === event.key.toLowerCase() && event.metaKey) {
            event.preventDefault()

            const windows = getAll()
            for (const window of windows) {
                if ('v2ray' === window.label) {
                    await window.close()
                }
            }
        }
    }

    document.onkeyup = async (event: KeyboardEvent) => {
        if (event.key.toLowerCase() === 'r' && event.metaKey) {
            window.location.reload()

            return
        }
    }

    await refresh_info()
    await refresh_routers(false)

    // 定时刷新
    if (ComponentV2rayState.Installing === state.state && undefined === state.auto_refresh) {
        state.auto_refresh = setInterval(async () => {
            await refresh_info()

            if (state.state !== ComponentV2rayState.NotInstall && ComponentV2rayState.Installing !== state.state && undefined != state.auto_refresh) {
                clearInterval(state.auto_refresh)
                state.auto_refresh = undefined
            }
        }, 1000)
    }
})

onUnmounted(async () => {
    if (undefined != state.auto_refresh) {
        clearInterval(state.auto_refresh)
        state.auto_refresh = undefined
    }
})

async function refresh_info(): Promise<void> {
    const response = await invoke_proxy<BackendResponse<ComponentV2rayInfo>>('invoke_component_v2ray_info')
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    state.version = response.data.version
    state.state = response.data.state
    state.install_stage = response.data.install_stage
    state.install_percent = response.data.install_percent
    state.basic_setting = response.data.basic_setting

    if (ComponentV2rayState.NotInstall === state.state) {
        await refresh_versions()
    }
}

async function refresh_versions(): Promise<void> {
    state.versions_loading = true
    const response = await invoke_proxy<BackendResponse<ComponentV2rayVersion[]>>('invoke_component_v2ray_versions')
    state.versions_loading = false
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)
        return
    }

    state.versions = []
    for (const version of response.data) {
        state.versions.push({
            label: version.version + '(发布时间:' + version.publish_time + ')',
            value: version.name + '###' + version.download,
            disabled: '' == version.download,
        })
    }
}

async function refresh_routers(message: boolean): Promise<void> {
    const response = await invoke_proxy<BackendResponse<ComponentV2rayRouter[]>>('invoke_component_v2ray_routers')
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    state.routers = response.data
    if (message) {
        window.Message.success('刷新完成')
    }
}

async function reset_routers(): Promise<void> {
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_reset_router')
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('重置完成')
    await refresh_routers(false)
}

async function install(): Promise<void> {
    if (undefined === state.select) {
        window.Message.error('请选择要安装的版本')
        return
    }

    // 定时刷新
    state.install_stage = '准备安装'
    state.install_percent = 0
    state.state = ComponentV2rayState.Installing
    if (undefined === state.auto_refresh) {
        state.auto_refresh = setInterval(async () => {
            await refresh_info()

            if (ComponentV2rayState.Installing !== state.state && undefined != state.auto_refresh) {
                clearInterval(state.auto_refresh)
                state.auto_refresh = undefined
            }
        }, 1000)
    }

    state.installing = true
    let tokens = state.select.split('###')
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_install', { name: tokens[0], url: tokens[1], reinstall: true })
    state.installing = false
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('安装成功')

    await refresh_info()
    await refresh_routers(false)
}

async function uninstall(): Promise<void> {
    // 拦截自动刷新
    if (undefined !== state.auto_refresh) {
        clearInterval(state.auto_refresh)
        state.auto_refresh = undefined
    }

    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_action', { action: 'Uninstall' })
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('卸载完成')
    state.state = ComponentV2rayState.NotInstall

    setTimeout(async () => await refresh_info(), 1000)
}

async function start(): Promise<void> {
    state.actioning = true
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_action', { action: 'Start' })
    state.actioning = false
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('启动成功')
    state.state = ComponentV2rayState.Running

    setTimeout(async () => await refresh_info(), 1000)
}

async function restart(): Promise<void> {
    state.actioning = true
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_action', { action: 'Restart' })
    state.actioning = false
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('重启成功')
    setTimeout(async () => await refresh_info(), 1000)
}

async function stop(): Promise<void> {
    state.actioning = true
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_action', { action: 'Stop' })
    state.actioning = false
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('停止成功')
    state.state = ComponentV2rayState.NotRunning

    setTimeout(async () => await refresh_info(), 1000)
}

async function save_basic_setting(): Promise<void> {
    state.basic_setting_saving = true
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_save_basic_setting', { setting: state.basic_setting })
    state.basic_setting_saving = false
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('保存成功')
    setTimeout(async () => await refresh_info(), 1000)
}

async function remove_router(router: ComponentV2rayRouter): Promise<void> {
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_remove_router', { router: router })
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('删除成功')
    await refresh_routers(false)
}

async function copy_as_shell_export(): Promise<void> {
    if (state.basic_setting.local_area_network) {
        dbus.emit('component:v2ray:copy-local-proxy')

        return
    }

    copy_to_clipboard(`export http_proxy="http://127.0.0.1:${state.basic_setting.http_port}"; export https_proxy="http://127.0.0.1:${state.basic_setting.http_port}"; export HTTP_PROXY="http://127.0.0.1:${state.basic_setting.http_port}"; export HTTPS_PROXY="http://127.0.0.1:${state.basic_setting.http_port}"`)
}

async function open_v2ray_path(): Promise<void> {
    const data_path = await appDataDir()
    const v2ray_path = await join(data_path, 'v2ray')

    const response = await invoke_proxy<BackendResponse<any>>('invoke_open', { path: v2ray_path })
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }
}

async function switch_udp(open: boolean): Promise<void> {
    state.basic_setting.udp = open
    await save_basic_setting()
}

async function switch_local_area_network(open: boolean): Promise<void> {
    state.basic_setting.local_area_network = open
    await save_basic_setting()
}

async function geosite_update(): Promise<void> {
    state.geosite_updating = true
    const response = await invoke_proxy<BackendResponse<any>>('invoke_component_v2ray_update_geosite')
    state.geosite_updating = false
    if (BACKEND_CODE_OK !== response.code) {
        window.Message.error(response.message)

        return
    }

    window.Message.success('更新成功')
    if (ComponentV2rayState.Running === state.state) {
        await restart()
    }
}
</script>

<template>
    <n-space :wrap="false" :wrap-item="false" vertical>
        <div class="title" data-tauri-drag-region>Magic Box V2ray组件</div>
        <template v-if="ComponentV2rayState.NotInstall === state.state || ComponentV2rayState.Installing === state.state || ComponentV2rayState.InstallFailed === state.state">
            <n-space :wrap="false" :wrap-item="false" align="center">
                <div class="max-flex-width">
                    <n-select v-model:value="state.select" :loading="state.versions_loading" :options="state.versions" placeholder="请选择安装版本" placement="bottom" size="small"></n-select>
                </div>
                <n-space :wrap="false" :wrap-item="false" align="center">
                    <n-button :loading="state.installing || ComponentV2rayState.Installing == state.state" size="small" type="info" @click="install">安装</n-button>
                    <n-button :disabled="state.installing || state.versions_loading" size="small" type="info" @click="refresh_versions">刷新列表</n-button>
                </n-space>
            </n-space>
            <template v-if="ComponentV2rayState.Installing === state.state || ComponentV2rayState.InstallFailed === state.state">
                <n-space :size="5" :wrap="false" :wrap-item="false" align="center" justify="center" style="margin-top: 240px" vertical>
                    <div>{{ state.install_stage }}</div>
                    <n-progress :percentage="state.install_percent" :show-indicator="false" class="max-width" processing status="info" type="line"></n-progress>
                </n-space>
            </template>
        </template>
        <template v-else>
            <n-space :wrap="false" :wrap-item="false" align="center">
                <n-space :wrap="false" :wrap-item="false" align="center" class="max-flex-width">
                    <div class="label">版本</div>
                    <div class="label">{{ state.version }}</div>
                    <div class="label">系统代理模式</div>
                    <div>
                        <n-select v-model:value="state.basic_setting.proxy_mode" :options="state.modes" placeholder="选择代理模式" size="small" style="width: 120px"></n-select>
                    </div>
                    <div>
                        <n-button :disabled="state.basic_setting_saving || state.switching" size="small" type="info" @click="save_basic_setting">切换</n-button>
                    </div>
                    <div class="label">SOCKS端口</div>
                    <div>
                        <n-input-number v-model:value="state.basic_setting.socket_port" max="65535" min="1" size="small" style="width: 100px"></n-input-number>
                    </div>
                    <div>
                        <n-button :disabled="state.basic_setting_saving || state.switching" size="small" type="info" @click="save_basic_setting">保存</n-button>
                    </div>
                    <div class="label">HTTP端口</div>
                    <div>
                        <n-input-number v-model:value="state.basic_setting.http_port" max="65535" min="1" size="small" style="width: 100px"></n-input-number>
                    </div>
                    <div>
                        <n-button :disabled="state.basic_setting_saving || state.switching" size="small" type="info" @click="save_basic_setting">保存</n-button>
                    </div>
                    <div class="label">状态</div>
                    <div class="label">
                        <n-text type="default">{{ ComponentV2rayState.NotRunning === state.state ? '未启动' : ComponentV2rayState.Running === state.state ? '已启动' : '异常退出' }}</n-text>
                    </div>
                    <n-space :wrap="false" :wrap-item="false" align="center">
                        <n-button v-if="ComponentV2rayState.NotRunning === state.state || ComponentV2rayState.Failed === state.state" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="info" @click="start">启动</n-button>
                        <n-button v-if="ComponentV2rayState.Running === state.state" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="info" @click="restart">重启</n-button>
                        <n-button v-if="ComponentV2rayState.Running === state.state" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="error" @click="stop">停止</n-button>
                        <n-button v-if="ComponentV2rayState.NotRunning === state.state || ComponentV2rayState.Failed === state.state" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="error" @click="uninstall">卸载</n-button>
                    </n-space>
                </n-space>
                <div>
                    <n-button size="small" type="info" @click="dbus.emit('component:v2ray:show-server-management')">服务器管理</n-button>
                    <!--                    <n-button size="small" type="info" @click="dbus.emit('component:v2ray:edit-pac-content')">编辑PAC脚本</n-button>-->
                </div>
            </n-space>
            <n-divider></n-divider>
            <n-space :wrap="false" :wrap-item="false" align="center">
                <n-button size="small" type="info" @click="open_v2ray_path">打开V2ray应用目录</n-button>
                <n-button size="small" type="info" @click="copy_as_shell_export">复制为命令行Export命令</n-button>
                <n-button v-if="!state.basic_setting.udp" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="info" @click="switch_udp(true)">开启UDP代理</n-button>
                <n-button v-if="state.basic_setting.udp" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="error" @click="switch_udp(false)">关闭UDP代理</n-button>
                <n-button v-if="!state.basic_setting.local_area_network" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="info" @click="switch_local_area_network(true)">允许局域网链接</n-button>
                <n-button v-if="state.basic_setting.local_area_network" :disabled="state.basic_setting_saving || state.switching || state.actioning" size="small" type="error" @click="switch_local_area_network(false)">关闭局域网链接</n-button>
                <n-button :loading="state.geosite_updating" size="small" type="info" @click="geosite_update">更新GEOSITE数据</n-button>
            </n-space>
            <n-divider></n-divider>
            <n-space :wrap="false" :wrap-item="false" align="center">
                <div style="width: 120px">
                    <n-button class="max-width" size="small" type="info" @click="refresh_routers(true)">刷新列表</n-button>
                </div>
                <div>
                    <n-button class="max-width" size="small" type="error" @click="reset_routers">重置路由规则</n-button>
                </div>
                <div class="max-flex-width">
                    <n-button class="max-width" size="small" type="info" @click="dbus.emit('component:v2ray:add-router')">添加路由规则</n-button>
                </div>
            </n-space>
            <n-space :wrap="false" :wrap-item="false" class="rules" vertical>
                <template v-for="router in state.routers" :key="router.uuid">
                    <n-space :wrap="false" :wrap-item="false" align="center" style="line-height: 1.5">
                        <div class="text-ellipsis" style="width: 120px">类型: {{ router.type }}</div>
                        <div class="text-ellipsis" style="width: 120px">预置规则: {{ router.preset ? '是' : '否' }}</div>
                        <div class="text-ellipsis max-flex-width">规则: {{ router.domain_or_ip_rule }}</div>
                        <n-space :wrap="false" :wrap-item="false" align="center">
                            <n-button size="small" type="error" @click="remove_router(router)">删除</n-button>
                        </n-space>
                    </n-space>
                </template>
            </n-space>
        </template>
        <ComponentV2rayServerManagement></ComponentV2rayServerManagement>
        <ComponentV2rayAddRouter @saved="refresh_routers(false)"></ComponentV2rayAddRouter>
        <ComponentV2rayCopyLocalProxy></ComponentV2rayCopyLocalProxy>
    </n-space>
</template>

<style lang="scss" scoped>
.title {
    font-size: 24px;
    line-height: 2;
    cursor: default;
    text-align: center;
}

.label {
    white-space: nowrap;
    text-wrap: none;
}

.rules {
    min-height: 360px;
    max-height: 65vh;
    overflow-y: auto;
}
</style>
